package com.heze.xunhuan.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heze.xunhuan.config.AppConfig;
import com.heze.xunhuan.dto.PostCreateDTO;
import com.heze.xunhuan.entity.Category;
import com.heze.xunhuan.entity.Post;
import com.heze.xunhuan.entity.User;
import com.heze.xunhuan.exception.BusinessException;
import com.heze.xunhuan.mapper.CategoryMapper;
import com.heze.xunhuan.mapper.PostMapper;
import com.heze.xunhuan.service.InteractionService;
import com.heze.xunhuan.service.PostService;
import com.heze.xunhuan.service.UserService;
import com.heze.xunhuan.utils.MinioUtil;
import com.heze.xunhuan.utils.RedisUtil;
import com.heze.xunhuan.utils.SecurityContextUtil;
import com.heze.xunhuan.vo.PageVO;
import com.heze.xunhuan.vo.PostVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 信息服务实现类
 *
 * @author heze-xunhuan
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {

    private final UserService userService;
    private final CategoryMapper categoryMapper;
    private final AppConfig appConfig;
    private final RedisUtil redisUtil;
    private final MinioUtil minioUtil;

    @Autowired
    @Lazy
    private InteractionService interactionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPost(Long userId, PostCreateDTO dto) {
        // 检查发布限制
        if (!userService.checkPostLimit(userId)) {
            throw new BusinessException(429, "今日发布数量已达上限");
        }

        // 验证分类
        Category category = categoryMapper.selectById(dto.getCategoryId());
        if (category == null) {
            throw new BusinessException(400, "分类不存在");
        }

        // 处理媒体文件上传
        List<String> mediaUrls = new ArrayList<>();
        if (dto.getMediaFiles() != null && !dto.getMediaFiles().isEmpty()) {
            for (MultipartFile file : dto.getMediaFiles()) {
                String url = minioUtil.uploadFile(file, "posts");
                mediaUrls.add(url);
            }
        }

        // 创建信息
        Post post = new Post();
        post.setUserId(userId);
        post.setCategoryId(dto.getCategoryId());
        post.setTitle(dto.getTitle());
        post.setContent(dto.getContent());
        post.setMediaType(dto.getMediaType() != null ? dto.getMediaType() : "image");
        post.setMediaUrls(JSONUtil.toJsonStr(mediaUrls));
        post.setLocationInfo(JSONUtil.toJsonStr(dto.getLocationInfo()));
        post.setContactInfo(JSONUtil.toJsonStr(dto.getContactInfo()));
        post.setViewCount(0);
        post.setLikeCount(0);
        post.setFavoriteCount(0);
        post.setStatus("pending");
        post.setDeleted(0);
        post.setCreatedAt(LocalDateTime.now());
        post.setUpdatedAt(LocalDateTime.now());

        // 设置过期时间
        Integer expireDays = appConfig.getBusiness().getPostExpireDays();
        post.setExpiredAt(LocalDateTime.now().plusDays(expireDays));

        this.save(post);

        // 增加用户发布数量
        userService.incrementPostCount(userId);

        return post.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePost(Long userId, Long postId, PostCreateDTO dto) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new BusinessException(404, "信息不存在");
        }
        if (!post.getUserId().equals(userId)) {
            throw new BusinessException(403, "无权限修改此信息");
        }
        if ("deleted".equals(post.getStatus())) {
            throw new BusinessException(400, "信息已删除");
        }

        // 处理媒体文件上传
        List<String> mediaUrls = new ArrayList<>();
        if (dto.getMediaFiles() != null && !dto.getMediaFiles().isEmpty()) {
            for (MultipartFile file : dto.getMediaFiles()) {
                String url = minioUtil.uploadFile(file, "posts");
                mediaUrls.add(url);
            }
        }

        post.setCategoryId(dto.getCategoryId());
        post.setTitle(dto.getTitle());
        post.setContent(dto.getContent());
        post.setMediaType(dto.getMediaType());
        post.setMediaUrls(JSONUtil.toJsonStr(mediaUrls));
        post.setLocationInfo(JSONUtil.toJsonStr(dto.getLocationInfo()));
        post.setContactInfo(JSONUtil.toJsonStr(dto.getContactInfo()));
        post.setStatus("pending"); // 修改后需要重新审核
        post.setUpdatedAt(LocalDateTime.now());

        this.updateById(post);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePost(Long userId, Long postId) {
        Post post = this.getById(postId);
        if (post == null) {
            throw new BusinessException(404, "信息不存在");
        }
        if (!post.getUserId().equals(userId)) {
            throw new BusinessException(403, "无权限删除此信息");
        }

        post.setStatus("deleted");
        post.setUpdatedAt(LocalDateTime.now());
        this.updateById(post);
    }

    @Override
    public PostVO getPostDetail(Long postId, Long currentUserId) {
        Post post = this.getById(postId);
        if (post == null || "deleted".equals(post.getStatus())) {
            throw new BusinessException(404, "信息不存在");
        }
        if (!"approved".equals(post.getStatus())) {
            // 只有发布者可以查看未审核的信息
            if (currentUserId == null || !post.getUserId().equals(currentUserId)) {
                throw new BusinessException(403, "信息审核中，暂不可查看");
            }
        }

        // 记录浏览
        recordView(postId);

        return convertToVO(post, currentUserId);
    }

    @Override
    public PageVO<PostVO> getPostPage(Integer page, Integer size, Integer categoryId, String subCategory,
                                       Double lat, Double lng, Double radius, String sortBy) {
        Page<Post> pageParam = new Page<>(page, size);
        String status = "approved";
        Double defaultRadius = radius != null ? radius : 10000.0; // 默认10公里

        IPage<Post> postPage = baseMapper.selectPostPage(pageParam, categoryId, subCategory, status,
                null, lat, lng, defaultRadius, sortBy != null ? sortBy : "time");

        List<PostVO> postVOList = postPage.getRecords().stream()
                .map(post -> convertToVO(post, SecurityContextUtil.getCurrentUserId()))
                .collect(Collectors.toList());

        return new PageVO<>(postVOList, page, size, postPage.getTotal());
    }

    @Override
    public PageVO<PostVO> searchPosts(Integer page, Integer size, String keyword, Integer categoryId,
                                       Double minPrice, Double maxPrice) {
        Page<Post> pageParam = new Page<>(page, size);
        IPage<Post> postPage = baseMapper.searchPosts(pageParam, keyword, categoryId, minPrice, maxPrice, "approved");

        List<PostVO> postVOList = postPage.getRecords().stream()
                .map(post -> convertToVO(post, SecurityContextUtil.getCurrentUserId()))
                .collect(Collectors.toList());

        return new PageVO<>(postVOList, page, size, postPage.getTotal());
    }

    @Override
    public PageVO<PostVO> getMyPosts(Long userId, Integer page, Integer size, String status) {
        Page<Post> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Post::getUserId, userId);
        if (status != null && !"all".equals(status)) {
            wrapper.eq(Post::getStatus, status);
        }
        wrapper.orderByDesc(Post::getCreatedAt);

        IPage<Post> postPage = this.page(pageParam, wrapper);

        List<PostVO> postVOList = postPage.getRecords().stream()
                .map(post -> convertToVO(post, userId))
                .collect(Collectors.toList());

        return new PageVO<>(postVOList, page, size, postPage.getTotal());
    }

    @Override
    public void recordView(Long postId) {
        String key = "post:view:" + postId;
        redisUtil.increment(key, 1);
        redisUtil.expire(key, 24, java.util.concurrent.TimeUnit.HOURS);

        // 异步更新数据库（可以定时任务批量更新）
        // 这里简化处理，直接更新
        Post post = this.getById(postId);
        if (post != null) {
            Object viewCount = redisUtil.get(key);
            if (viewCount != null) {
                post.setViewCount(Integer.parseInt(viewCount.toString()));
                this.updateById(post);
            }
        }
    }

    @Override
    public Object getPostLimit(Long userId) {
        User user = userService.getById(userId);
        if (user == null) {
            throw new BusinessException(404, "用户不存在");
        }

        Integer limit = (user.getVipLevel() != null && user.getVipLevel() > 0)
                ? appConfig.getBusiness().getVipDailyPostLimit()
                : appConfig.getBusiness().getDailyPostLimit();

        LocalDateTime now = LocalDateTime.now();
        boolean isNewDay = user.getLastPostDate() == null ||
                !user.getLastPostDate().equals(now.toLocalDate());

        Map<String, Object> result = new HashMap<>();
        result.put("dailyLimit", limit);
        result.put("usedCount", isNewDay ? 0 : user.getDailyPostCount());
        result.put("remainingCount", Math.max(0, limit - (isNewDay ? 0 : user.getDailyPostCount())));
        result.put("resetTime", now.toLocalDate().plusDays(1).atStartOfDay());

        return result;
    }

    /**
     * 转换为VO
     */
    private PostVO convertToVO(Post post, Long currentUserId) {
        PostVO postVO = new PostVO();
        BeanUtils.copyProperties(post, postVO);

        // 设置用户信息
        User user = userService.getById(post.getUserId());
        if (user != null) {
            PostVO.UserInfo userInfo = new PostVO.UserInfo();
            userInfo.setId(user.getId());
            userInfo.setNickname(user.getNickname());
            userInfo.setAvatar(user.getAvatar());
            postVO.setUserInfo(userInfo);
        }

        // 设置分类信息
        Category category = categoryMapper.selectById(post.getCategoryId());
        if (category != null) {
            PostVO.CategoryInfo categoryInfo = new PostVO.CategoryInfo();
            categoryInfo.setId(category.getId());
            categoryInfo.setName(category.getName());
            categoryInfo.setIcon(category.getIcon());
            postVO.setCategoryInfo(categoryInfo);
        }

        // 解析媒体URLs
        if (post.getMediaUrls() != null) {
            List<String> mediaUrls = JSONUtil.toList(post.getMediaUrls(), String.class);
            postVO.setMediaUrls(mediaUrls);
        }

        // 解析位置信息
        if (post.getLocationInfo() != null) {
            Map<String, Object> locationMap = JSONUtil.toBean(post.getLocationInfo(), Map.class);
            PostVO.LocationInfo locationInfo = new PostVO.LocationInfo();
            locationInfo.setAddress((String) locationMap.get("address"));
            if (locationMap.get("lat") != null) {
                locationInfo.setLat(Double.parseDouble(locationMap.get("lat").toString()));
            }
            if (locationMap.get("lng") != null) {
                locationInfo.setLng(Double.parseDouble(locationMap.get("lng").toString()));
            }
            postVO.setLocationInfo(locationInfo);
        }

        // 设置统计数据
        PostVO.Stats stats = new PostVO.Stats();
        stats.setViewCount(post.getViewCount());
        stats.setLikeCount(post.getLikeCount());
        stats.setFavoriteCount(post.getFavoriteCount());
        postVO.setStats(stats);

        // 设置是否点赞和收藏
        if (currentUserId != null) {
            postVO.setIsLiked(interactionService.isLiked(currentUserId, post.getId()));
            postVO.setIsCollected(interactionService.isFavorited(currentUserId, post.getId()));
        } else {
            postVO.setIsLiked(false);
            postVO.setIsCollected(false);
        }

        return postVO;
    }
}